#include "XlsxReader.h"

#include <OpenXLSX/headers/XLCellValue.hpp>
#include <iostream>
#include <zlog.h>

static const int DEVNAME_COL_NUM    = 4;  // 所属产品转发设备名称
static const int VARNAME_COL_NUM    = 8;  // 转发数据简称
static const int DESC_COL_NUM       = 7;  // 转发数据点名称
static const int RETRANSMIT_COL_NUM = 16; // 转发参数列
static const int ORI_MIN_COL_NUM    = 11; // 原数据最小值列
static const int ORI_MAX_COL_NUM    = 12; // 原数据最大值列
static const int REL_MIN_COL_NUM    = 13; // 实数据最小值列
static const int REL_MAX_COL_NUM    = 14; // 实数据最大值列

std::vector<Data> XlsxReader::dataList;

XlsxReader::XlsxReader() {}

XlsxReader::~XlsxReader() { CloseFile(); }

void XlsxReader::OpenFile(std::string filename) {

    try {
        zlog_i("尝试打开: %s", filename.c_str());
        doc.open(filename);
    }
    catch (const std::exception &e) {
        zlog_i("%s", e.what());
    }
}

void XlsxReader::CloseFile() { doc.close(); }

void XlsxReader::Parse() {

    auto wks = doc.workbook().worksheet("产品转发数据点表");
    dataList.clear();

    std::string              line;
    std::vector<XLCellValue> rowValues; //

    zlog_i("Total %d rows", wks.rowCount());
    for (auto &row : wks.rows()) {
        // Skip the first row
        if (row.rowNumber() == 1) {
            continue;
        }

        rowValues = row.values();
        Data data;
        data.sAddr = row.rowNumber();

        try {
            if (!rowValues[DEVNAME_COL_NUM].get<std::string>().empty()) {
                data.devName = Util::FilterChineseCharacter(
                    rowValues[DEVNAME_COL_NUM].get<std::string>());

                // data.devName = data.devName.substr(0, 2);
            }

            if (!rowValues[VARNAME_COL_NUM].get<std::string>().empty()) {
                data.varName = rowValues[VARNAME_COL_NUM].get<std::string>();
            }

            if (!rowValues[DESC_COL_NUM].get<std::string>().empty()) {
                data.desc = rowValues[DESC_COL_NUM].get<std::string>();
            }

            if (!rowValues[RETRANSMIT_COL_NUM].get<std::string>().empty()) {
                data.type       = JudgeDataType(rowValues[RETRANSMIT_COL_NUM],
                                          rowValues[ORI_MIN_COL_NUM],
                                          rowValues[ORI_MAX_COL_NUM],
                                          rowValues[REL_MIN_COL_NUM],
                                          rowValues[REL_MAX_COL_NUM]);
                data.isReadable = JudgeReadable(rowValues[RETRANSMIT_COL_NUM]);
                data.isWritable = JudgeWritable(rowValues[RETRANSMIT_COL_NUM]);
            }
        }
        catch (const std::exception &e) {
            zlog_e("row number: %ld ,%s", row.rowNumber(), e.what());
        }

        // 判断是否可读
        dataList.push_back(data);
    }
}

DataType XlsxReader::JudgeDataType(XLCellValue retransParas,
                                   XLCellValue originalMinValue,
                                   XLCellValue originalMaxValue,
                                   XLCellValue realMinValue,
                                   XLCellValue realMaxValue) {
    // 判断数据类型
    // BOOL 通过转发参数 判断
    std::string              str       = retransParas.get<std::string>();
    char                     delimiter = '_';
    std::vector<std::string> tokens    = Util::SplitString(str, delimiter);

    if (tokens[4] == "B") {
        char last  = tokens[6].back();
        char last2 = tokens[6].at(tokens[6].size() - 2);
        if (last == '1' && last2 == '.') {
            return DataType::BOOL;
        }
    }

    std::variant<float, int> originalMinNum = GetValue(originalMinValue);
    std::variant<float, int> originalMaxNum = GetValue(originalMaxValue);
    std::variant<float, int> realMinNum     = GetValue(realMinValue);
    std::variant<float, int> realMaxNum     = GetValue(realMaxValue);

    // INT 缩放系数为1
    if (CompareVariants(originalMaxNum, realMaxNum)) {
        // zlog_i("发现整数");
        return DataType::INT;
    }
    // INT 是否有偏移

    auto oriRange  = SubtractVariants(originalMaxNum, originalMinNum);
    auto realRange = SubtractVariants(realMaxNum, realMinNum);

    if (CompareVariants(oriRange, realRange)) {
        // zlog_i("发现整数");
        return DataType::INT;
    }

    return DataType::FLOAT;
}

bool XlsxReader::JudgeReadable(XLCellValue retransParas) {
    // 判断是否可读
    try {
        std::string str = retransParas.get<std::string>();
        if (str.size() < 2) {
            std::cout << "Error 转发参数长度不对: " << str << std::endl;
            return false;
        }

        char last  = str.back();
        char last2 = str.at(str.size() - 2);
        if (last == 'R' || last2 == 'R') {
            return true;
        }

        return false;
    }
    catch (const std::exception &e) {
        zlog_e("判断可读错误: %s", retransParas.get<std::string>().c_str());
    }
    return false;
}

bool XlsxReader::JudgeWritable(XLCellValue retransParas) {
    // 判断是否可写
    try {
        std::string str = retransParas.get<std::string>();
        if (str.size() < 2) {
            std::cout << "Error 转发参数长度不对: " << str << std::endl;
            return false;
        }

        char last  = str.back();
        char last2 = str.at(str.size() - 2);
        if (last == 'W' || last2 == 'W') {
            return true;
        }
    }
    catch (const std::exception &e) {
        zlog_e("判断可写错误: %s", retransParas.get<std::string>().c_str());
    }
    return false;
}

std::variant<float, int> XlsxReader::GetValue(const XLCellValue &value) {
    if (value.type() == XLValueType::Float) {
        return value.get<float>();
    }
    else {
        return value.get<int>();
    }
}

std::variant<float, int>
XlsxReader::SubtractVariants(const std::variant<float, int> &a,
                             const std::variant<float, int> &b) {
    return std::visit(
        [](auto &&lhs, auto &&rhs) -> std::variant<float, int> {
            using T = std::common_type_t<decltype(lhs), decltype(rhs)>;
            return static_cast<T>(lhs - rhs);
        },
        a,
        b);
}

// 帮助函数，比较两个variant是否相等
bool XlsxReader::CompareVariants(const std::variant<float, int> &a,
                                 const std::variant<float, int> &b) {
    return std::visit(
        [](auto &&lhs, auto &&rhs) {
            return lhs == rhs;
        },
        a,
        b);
}
